<?php

namespace app\service;

use app\model\ProjectModel;
use app\model\TaskModel;
use app\model\TaskWorkOrderModel;
use app\model\TaskWorkOrderProblemStepCategoryModel;
use app\model\TaskWorkOrderUserModel;
use app\tool\SingletonTrait;

use function DI\string;

class TaskWorkOrderService
{
    use SingletonTrait;

    protected $projectModel;
    protected $taskModel;
    protected $taskWorkOrderModel;
    protected $taskWorkOrderUserModel;
    protected $taskWorkOrderProblemStepCategoryModel;

    // 工单处理状态(0:未处理,1:已处理,2:已失效,3:处理中)
    const TASK_WORD_ORDER_STATUS_NOT_PROCESSED = 0;
    const TASK_WORD_ORDER_STATUS_PROCESSED = 1;
    const TASK_WORD_ORDER_STATUS_EXPIRED = 2;
    const TASK_WORD_ORDER_STATUS_PROCESSING = 3;

    // 工单默认处理状态 未处理的数据
    public $taskWorkOrderStatusDefault = [
        self::TASK_WORD_ORDER_STATUS_NOT_PROCESSED,
        self::TASK_WORD_ORDER_STATUS_PROCESSING
    ];

    // project status 项目状态
    const PROJECT_STATUS_START = 1; // 未开始
    const PROJECT_STATUS_COMPLETED = 4; //进行中
    const PROJECT_STATUS_CANCEL = 3; // 取消
    const PROJECT_STATUS_IN_PROGRESS = 7;     // 已完成


    public function __construct()
    {
        $this->projectModel = new ProjectModel();
        $this->taskModel = new TaskModel();
        $this->taskWorkOrderModel = new TaskWorkOrderModel();
        $this->taskWorkOrderProblemStepCategoryModel = new TaskWorkOrderProblemStepCategoryModel();
        $this->taskWorkOrderUserModel = new TaskWorkOrderUserModel();
    }


    /**
     * 工单统计
     * @param array $param
     * @param string $tenant_id
     */
    public function getTaskWorkOrderStatistics(array $param, string $tenant_id)
    {
        $project_id = $param['project_id'];
        $projectIds = $this->getProjectData($project_id);
        return $this->getProjectTaskInfo($projectIds, $param, $tenant_id);
    }

    /**
     * 获取项目字典数据
     */
    public function getProjectData($project_id)
    {
        $projectRes = $this->projectModel
            ->field(['id'])
            ->whereRaw("belong_project_id = $project_id")
            ->whereFieldRaw(
                "get_json_string(project.`json`, 'project_status')",
                'IN',
                [self::PROJECT_STATUS_START, self::PROJECT_STATUS_COMPLETED, self::PROJECT_STATUS_IN_PROGRESS, self::PROJECT_STATUS_CANCEL]
            )
            ->select()->toArray();
        $projectIds = [];
        if (!empty($projectRes)) {
            $projectIds = array_unique(array_column($projectRes, 'id'));
        }
        array_push($projectIds, (string)$project_id);
        return $projectIds;
    }


    /**
     * 根据项目id 时间段 节点数据 获取工单数据计算
     * @param $projectIds
     * @param array $param
     * @param string $tenant_id
     * @return array
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function getProjectTaskInfo($projectIds, array $param, string $tenant_id)
    {
        $data = [];
        if(empty($projectIds)){
            $data['send_work_order'] = ['processed' => 0, 'not_processed' => 0];
            $data['receive_work_order'] = ['processed' => 0, 'not_processed' => 0];
            return $data;
        //如果用户没有传环节,部门，用户
        }
        //按环节计算
        if (!empty($param['step_category_id'])) {
            //发出工单数据
            $sendRealCount = $this->sendTaskWorkOrderCount($projectIds, $param, $tenant_id);
            $data['send_work_order'] = $sendRealCount;
        }
        // 按部门计算
        if (!empty($param['department_id'])) {
            $sendRealCount = $this->getDepartmentTeamTaskWorkOrderList($projectIds, $param, $tenant_id);
            $data['send_work_order'] = $sendRealCount;
        }
        // 按用户
        if (!empty($param['user_id'])) {
            $sendRealCount = $this->getUserTaskWorkOrderList($projectIds, $param, $tenant_id);
            $data['send_work_order'] = $sendRealCount;
        }
        //收到的工单数据
        $sendCount = $this->receiveTaskWorkOrderCount($projectIds, $param, $tenant_id);
        $data['receive_work_order'] = $sendCount;
        return $data;
    }

    /**
     * @param $sendCount
     * @param $sendRealCount
     * @return array
     */
    private function _sendWorkOrderCount($sendCount, $sendRealCount)
    {
        $data = [];
        $data['processed'] = $sendCount['processed'] + $sendRealCount['processed'];
        $data['not_processed'] = $sendCount['not_processed'] + $sendRealCount['not_processed'];

        return $data;
    }

    public function getOutProjectTaskInfo($project, array $param, string $tenant_id)
    {
        //获取项目ids
        $ids = [];
        $belong_ids = [];
        foreach ($project as $key => $value) {
            $belong_ids[] = $value['belong_project_id'];
            $ids[] = $value['id'];
        }

        $project_ids = array_unique(array_merge($belong_ids, $ids));
        //发出去的工单
        $data['send_work_order'] = $this->sendOutTaskWorkOrderCount(array_unique($belong_ids), $param);
        //收到的工单 receiveTaskWorkOrderCount
        $data['receive_work_order'] = $this->receiveOutTaskWorkOrderCount($project_ids, $param, $tenant_id);
        return $data;
    }

    /**
     * 乙方申请的工单数据
     * @param $projectIds
     * @param $param
     * @return int
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function sendOutTaskWorkOrderCount($projectIds, $param)
    {
        $project_id = implode(',', $projectIds);
        $data = $this->taskWorkOrderModel
            ->where([
                'project_id' => $project_id,
                'type' => 'task_making',
                'step_category_id' => $param['step_category_id']
            ])
            ->whereIn('status', [self::TASK_WORD_ORDER_STATUS_NOT_PROCESSED, self::TASK_WORD_ORDER_STATUS_PROCESSED, self::TASK_WORD_ORDER_STATUS_PROCESSING])
            ->whereBetweenTime('created', $param['start_time'], $param['end_time'])
            ->select();

        $processed = [];
        $not_processed = [];
        foreach ($data as $item) {
            //已处理
            if ($item['status'] == self::TASK_WORD_ORDER_STATUS_PROCESSED) {
                $processed[] = $item;
            } else {
                // 未处理
                $not_processed[] = $item;
            }
        }

        return ['processed' => count($processed), 'not_processed' => count($not_processed)];
    }

    /**
     * 外包收的工单数据
     * @param $projectIds
     * @param $param
     * @return void
     */
    public function receiveOutTaskWorkOrderCount($projectIds, $param, $tenant_id)
    {
        $taskIds = $this->taskWorkOrderUserModel
            ->distinct(true)
            ->whereBetweenTime('created', $param['start_time'], $param['end_time'])
            ->where('user_id', 'in', function ($query) use ($tenant_id) {
                $query->name('user')->where('union_id', 'in', function ($query) use ($tenant_id) {
                    $query->name('user')->where('id', 'in', function ($query) use ($tenant_id) {
                        $query->name('tenant_user')->where('tenant_id', $tenant_id)->field('user_id');
                    })->field('id');
                })->field('id');
            })->column('work_order_id');

        $project_id = implode(',', $projectIds);
        $data = $this->taskWorkOrderModel
            ->where([
                'type' => 'task_making',
                'step_category_id' => $param['step_category_id']
            ])
            ->whereIn('status', [self::TASK_WORD_ORDER_STATUS_NOT_PROCESSED, self::TASK_WORD_ORDER_STATUS_PROCESSED, self::TASK_WORD_ORDER_STATUS_PROCESSING])
            ->whereIn('task_id', $taskIds)
            ->whereIn('project_id', $project_id)
            ->whereBetweenTime('created', $param['start_time'], $param['end_time'])
            ->select();

        $processed = [];
        $not_processed = [];
        foreach ($data as $item) {
            //已处理
            if ($item['status'] == self::TASK_WORD_ORDER_STATUS_PROCESSED) {
                $processed[] = $item;
            } else {
                // 未处理
                $not_processed[] = $item;
            }
        }

        return ['processed' => count($processed), 'not_processed' => count($not_processed)];
    }

    /** 按环节统计的工单数据
     * @param $project_id
     * @param $param
     * @return array
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function sendTaskWorkOrderCount($projectIdList, $param, $tenant_id)
    {
        $processed = [];
        $not_processed = [];
        $dbr = $this->taskWorkOrderModel
            ->field(['task_w_o.id,task_w_o.status,task_w_o.type,task_w_o.step_category_id,task_w_o.project_id,task_w_o.created,twopsc.is_confirm'])
            ->alias('task_w_o')
            ->distinct(true)
            ->join(['task_work_order_problem_step_category' => 'twopsc'], 'twopsc.task_work_order_id = task_w_o.id', 'left')
            ->join(['task' => 'task'], 'task.id = task_w_o.task_id', 'inner')
            ->join(['entity'], 'entity.id = task.entity_id', 'inner')
            ->join(['module' => 'module'], 'entity.module_id = module.id', 'inner')
            ->whereRaw("get_json_string(entity.`json`, concat('$.', module.code, '_status')) <> 3")
            ->whereIn('task_w_o.step_category_id', explode(',', $param['step_category_id']))
            ->whereIn('task_w_o.status', [self::TASK_WORD_ORDER_STATUS_NOT_PROCESSED, self::TASK_WORD_ORDER_STATUS_PROCESSED, self::TASK_WORD_ORDER_STATUS_PROCESSING])
            ->whereIn('twopsc.is_confirm', ['default', 'yes', 'no'])
            ->where(
                [
                    'task_w_o.type' => 'task_making',
                ]
            )
            ->whereIn('task_w_o.project_id', $projectIdList);
        $data = $dbr->whereBetweenTime('task_w_o.created', $param['start_time'], $param['end_time'])->select();

        if (empty($data)) {
            return ['processed' => count($processed), 'not_processed' => count($not_processed)];
        }
        $uniqueData = [];
        $uniqueIds = [];
        //去重
        foreach ($data as $item) {
            $id = $item['id'];
            if (!in_array($id, $uniqueIds)) {
                $uniqueData[] = $item;
                $uniqueIds[] = $id;
            }
        }

        foreach ($uniqueData as $key => $item) {
            // 发出的工单未确认
            if ($item['is_confirm'] == 'default' && $item['status'] != self::TASK_WORD_ORDER_STATUS_PROCESSED) {
                $not_processed[$key] = $item;
            }
            // 已解决
            if ($item['is_confirm'] != 'default') {
                $processed[$key] = $item;
            }
        }
        return ['processed' => count($processed), 'not_processed' => count($not_processed)];

    }

    /**
     * 收到的工单数据
     * @param $ProjectId
     * @param $param
     * @return array
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function receiveTaskWorkOrderCount($projectIds, $param, $tenant_id)
    {
        $processed     = [];
        $not_processed = [];

        $field = ['task_w_o.id,task_w_o.status,task_w_o.type,task_w_o.step_category_id,twopsc.step_category_id as twopsc_step_category_id ,task_w_o.project_id,task_w_o.created,twopsc.is_confirm'];

        if (!empty($param['step_category_id'])) {
            $dbr = $this->taskWorkOrderModel
                ->field($field)
                ->alias('task_w_o')
                ->distinct(true)
                ->join(['task_work_order_problem_step_category' => 'twopsc'], 'twopsc.task_work_order_id = task_w_o.id', 'left')
                ->where(
                    [
                        'task_w_o.type' => 'task_making',
                    ]
                )
                ->where('twopsc.step_category_id', $param['step_category_id'])
                ->whereIn('task_w_o.status', [self::TASK_WORD_ORDER_STATUS_NOT_PROCESSED, self::TASK_WORD_ORDER_STATUS_PROCESSED, self::TASK_WORD_ORDER_STATUS_PROCESSING])
                ->whereIn('twopsc.is_confirm', ['default', 'yes', 'no'])
                ->whereIn('task_w_o.project_id', $projectIds);
        }

        // 按部门查找
        if (!empty($param['department_id'])) {
            $userIds = $this->getDepartmenByUserId($param['department_id']);

            $dbr = $this->taskWorkOrderModel
                ->field(['task_w_o.id,task_w_o.category_id,task_w_o.status,task_w_o.type,task_w_o.step_category_id,task_w_o.project_id,task_w_o.created'])
                ->alias('task_w_o')
                ->distinct(true)
                ->join(['task_work_order_user' => 'twou'], 'twou.work_order_id = task_w_o.id', 'left')
                ->join(['task' => 'task'], 'task.id = task_w_o.task_id', 'left')
                ->join(['entity' => 'entity'], 'entity.id = task.entity_id', 'left')
                ->join(['module' => 'module'], 'entity.module_id = module.id', 'left')
                ->where(
                    [
                        'task_w_o.type' => 'task_making',
                    ]
                )
                ->whereIn('task_w_o.project_id', $projectIds)
                ->whereIn('twou.user_id', $userIds)
                ->whereRaw("get_json_string(entity.`json`, concat('$.', module.code, '_status')) <> 3")
                ->whereIn('task_w_o.status', [self::TASK_WORD_ORDER_STATUS_NOT_PROCESSED, self::TASK_WORD_ORDER_STATUS_PROCESSED, self::TASK_WORD_ORDER_STATUS_PROCESSING]);
        }

        // 按用户查找
        if (!empty($param['user_id'])) {
            // 按用户算相关工单都要看到
            $taskIds = $this->taskWorkOrderUserModel
                ->distinct(true)
                ->whereBetweenTime('created', $param['start_time'], $param['end_time'])
                ->where('user_id', 'in', function ($query) use ($tenant_id) {
                    $query->name('user')->where('union_id', 'in', function ($query) use ($tenant_id) {
                        $query->name('user')->where('id', 'in', function ($query) use ($tenant_id) {
                            $query->name('tenant_user')->where('tenant_id', $tenant_id)->field('user_id');
                        })->field('id');
                    })->field('id');
                })->column('work_order_id');

            $dbr = $this->taskWorkOrderModel
                ->field($field)
                ->alias('task_w_o')
                ->distinct(true)
                ->join(['task_work_order_problem_step_category' => 'twopsc'], 'twopsc.task_work_order_id = task_w_o.id', 'left')
                ->join(['task_work_order_user' => 'twou'], 'twou.work_order_id = task_w_o.id', 'left')
                ->where(
                    [
                        'task_w_o.type' => 'task_making',
                        'twou.user_id' => $param['user_id'],
                    ]
                )
                ->whereIn('task_w_o.project_id', $projectIds)
                ->where('twopsc.step_category_id', $param['step_category_id'])
                ->whereIn('task_w_o.status', [self::TASK_WORD_ORDER_STATUS_NOT_PROCESSED, self::TASK_WORD_ORDER_STATUS_PROCESSED, self::TASK_WORD_ORDER_STATUS_PROCESSING])
                ->whereIn('twopsc.is_confirm', ['default', 'yes', 'no'])
                ->whereIn('task_w_o.id', $taskIds);
        }
        $data = $dbr->whereBetweenTime('task_w_o.created', $param['start_time'], $param['end_time'])->order('task_w_o.id')->select();



        if (empty($data)) {
            return ['processed' => count($processed), 'not_processed' => count($not_processed)];
        }
        foreach ($data as $key => $item) {
            // 发出的工单未确认
            if ($item['is_confirm'] == 'default' && $item['status'] != self::TASK_WORD_ORDER_STATUS_PROCESSED) {
                $not_processed[$key] = $item;
            }
            // 已确认
            if ($item['is_confirm'] != 'default' && $item['status'] == self::TASK_WORD_ORDER_STATUS_PROCESSED) {
                $processed[$key] = $item;
            }
        }

        return ['processed' => count($processed), 'not_processed' => count($not_processed)];
    }

    /**
     * 获取部门下的用户列表
     * @param $department_id
     * @return array|mixed
     */
    public function getDepartmenByUserId(int $department_id)
    {
        $departmentUserList = teamones_request('teamones-saas', 'tenant/select_department_user', ["param" => [
            "filter" => [
                "department_id" => $department_id,
            ]
        ]])['data']['rows'] ?? [];

        $userIds = [];
        foreach ($departmentUserList as $key => $value){
            $userIds[] = $value['saas_user_id'];
        }
        return $userIds;
    }

    /**
     * 根据租户分类获取不同的项目id
     * @param $project
     * @param $tenant_id
     * @return array
     */
    public function getProjectIdOrBelongProjectId($project, $tenant_id)
    {
        $projectIds = [];
        if ($tenant_id == 1) {
            $paryAids = [];
            $paryBids = [];
            foreach ($project as $key => $value) {
                if ($value['belong_project_id'] > 0) {
                    $paryBids[] = $value['id'];
                    $paryAids[] = $value['belong_project_id'];
                } else {
                    $paryAids[] = $value['id'];
                }
            }

            $projectIds = array_merge($paryAids, $paryBids);
        } else {
            foreach ($project as $key => $value) {
                if ($value['belong_project_id'] > 0) {
                    $projectIds[] = $value['id'];
                }
            }
        }

        return $projectIds;
    }

    /**
     * 按部门进行计算发出的工单
     * @return void
     */
    public function getDepartmentTeamTaskWorkOrderList($projectIdList, $param, $tenant_id)
    {

        $processed = [];
        $not_processed = [];

        //获取部门下的用户所有的用户 id
        $saasUserIds = $this->getDepartmenByUserId($param['department_id']);
        $dbr = $this->taskWorkOrderModel
            ->field('task_w_o.id,task_w_o.category_id,task_w_o.status,task_w_o.type,task_w_o.step_category_id,task_w_o.project_id,task_w_o.created,twopsc.is_confirm')
            ->alias('task_w_o')
            ->join(['task_work_order_user' => 'twou'], ' twou.work_order_id = task_w_o.id', 'inner')
            ->join(['task_work_order_problem_step_category' => 'twopsc'], 'twopsc.task_work_order_id = task_w_o.id', 'inner')
            ->join(['task'], 'task.id = task_w_o.task_id', 'inner')
            ->join(['entity'], 'entity.id = task.entity_id', 'inner')
            ->join(['module' => 'module'], 'entity.module_id = module.id', 'inner')
            ->where(
                [
                    'task_w_o.type' => 'task_making',
                    'task_w_o.tenant_id' => $tenant_id
                ]
            )
            ->whereRaw("get_json_string(entity.`json`, concat('$.', module.code, '_status')) <> 3")
            ->whereBetweenTime('task_w_o.created', $param['start_time'], $param['end_time'])
            ->whereIn('task_w_o.status', [self::TASK_WORD_ORDER_STATUS_NOT_PROCESSED, self::TASK_WORD_ORDER_STATUS_PROCESSED, self::TASK_WORD_ORDER_STATUS_PROCESSING])
            ->whereIn('twopsc.is_confirm', ['default', 'yes', 'no'])
            ->whereIn('twou.user_id', $saasUserIds)
            ->whereIn('task_w_o.project_id', $projectIdList);
        $data = $dbr->order('task_w_o.id desc')->select();

        // dump('部门发出的工单',$dbr->getLastSql());

        if (empty($data)) {
            return ['processed' => count($processed), 'not_processed' => count($not_processed)];
        }

        foreach ($data as $key => $item) {
            // // 发出的工单未确认
            if ($item['is_confirm'] == 'default' && $item['status'] != self::TASK_WORD_ORDER_STATUS_PROCESSED) {
                $not_processed[$key] = $item;
            }
            // 已解决
            if ($item['is_confirm'] != 'default') {
                $processed[$key] = $item;
            }
        }
        return ['processed' => count($processed), 'not_processed' => count($not_processed)];
    }


    /**
     * @param $param
     * @param $projectIdList
     * @param $tenant_id
     * @param $isPartyB
     * @return array
     */
    public function getUserTaskWorkOrderList($param, $projectIdList, $tenant_id)
    {
        // 指定用户的工单id
        $work_order_id = $this->_getByUserIdTaskId($param);

        $processed = [];
        $not_processed = [];

        if (empty($work_order_id)) {
            return ['processed' => count($processed), 'not_processed' => count($not_processed)];
        }

        $taskWorkOrderData = $this->taskWorkOrderModel
            ->alias('task_w_o')
            ->join(['task_work_order_problem_step_category' => 'twopsc'], 'twopsc.task_work_order_id = task_w_o.id', 'left')
            ->where(['project_id' => $param['project_id'], 'type' => 'task_making', 'tenant_id' => $tenant_id])
            ->where('twopsc.step_category_id', $param['step_category_id'])
            ->whereIn('task_id', $work_order_id)
            ->whereIn('twopsc.is_confirm', ['default', 'yes', 'no'])
            ->whereIn('status', [self::TASK_WORD_ORDER_STATUS_NOT_PROCESSED, self::TASK_WORD_ORDER_STATUS_PROCESSING, self::TASK_WORD_ORDER_STATUS_PROCESSED])
            ->whereBetweenTime('created', $param['start_time'], $param['end_time'])
            ->group('task_w_o.id')
            ->select();

        if (empty($taskWorkOrderData)) {
            return ['processed' => count($processed), 'not_processed' => count($not_processed)];
        }
        foreach ($taskWorkOrderData as $key => $item) {
            if ($item['is_confirm'] == 'default' && $item['status'] != self::TASK_WORD_ORDER_STATUS_PROCESSED) {
                $not_processed[$key] = $item;
            }
            // 已解决
            if ($item['is_confirm'] != 'default') {
                $processed[$key] = $item;
            }
        }
        return ['processed' => count($processed), 'not_processed' => count($not_processed)];
    }

    /**
     * 获取指定用户任务task_workd_id 工单id
     * @param $param
     * @return mixed
     */
    private function _getByUserIdTaskId($param)
    {
        return $this->taskWorkOrderUserModel
            ->distinct(true)
            ->whereBetweenTime('created', $param['start_time'], $param['end_time'])
            ->where(['user_id' => $param['user_id']])
            ->column('work_order_id');
    }

}
